﻿using System;
using System.Text;
using System.IO;

namespace Technullogy
{
    public static class TechnullogyLogging
    {
        #region Declarations
        private const String SYNC_STARTED = "Technullogy Directory Sync started at {0}";
        private const String SYNC_DURATION = "Technullogy Directory Sync duration: {0}";
        private const String SYNC_FINISHED = "Technullogy Directory Sync finished at {0}";

        private const String DELETE_STARTED = "Technullogy Directory Empty Directory Delete started at {0}";
        private const String DELETE_DURATION = "Technullogy Directory Empty Directory Delete duration: {0}";
        private const String DELETE_FINISHED = "Technullogy Directory Empty Directory Delete finished at {0}";

        private const String LOADING_DIR = "Loading directory {0}";
        private const String CREATING_DIR = "Creating directory: {0}";
        private const String DIR_EXISTS = "Directory {0} already exists";
        private const String DIR_DELETED = "Deleting directory: {0}";

        private const String COPYING_FILE = "Copying from {0} to {1}";
        private const String FILE_EXISTS = "File {0} already exists in the destination folder";
        private const String FILE_SKIPPED = "File {0} skipped";
        private const String FILE_DELETED = "File {0} deleted";

        private const String DIRS_DELETED = "{0} directories deleted";
        private const String FILES_DELETED = "{0} files deleted";

        private const String NEW_LINE = "\r\n";
        
        private const String DIRS_CREATED = "Created {0} directories";
        private const String FILES_CREATED = "Copied {0} files";
        private const String OVERWRITING_FILE = "Overwriting file {0} ({1} bytes) with file {2} ({3} bytes)";
        private const String HORIZONTAL_RULE = "_____________________________________________________";
        #endregion


        #region Properties
        private static StringBuilder _log;
        public static StringBuilder Log
        {
            get
            {
                if (_log == null)
                    _log = new StringBuilder();
                return _log;
            }
        }

        public static int LocalToRemoteFileCount { get; set; }
        public static int RemoteToLocalFileCount { get; set; }
        public static int LocalToRemoteDirectoryCount { get; set; }
        public static int RemoteToLocalDirectoryCount { get; set; }
        public static bool IsLocalToRemote { get; set; }

        public static int LocalDirectoriesDeleteCount { get; set; }
        public static int LocalFilesDeleteCount { get; set; }
        public static int RemoteDirectoriesDeleteCount { get; set; }
        public static int RemoteFilesDeleteCount { get; set; }
        #endregion


        #region Methods
        public static void LogDirectorySyncStarted(DateTime start)
        {
            Console.WriteLine(String.Format(DELETE_STARTED, start));

            Log.Append(NEW_LINE);
            Log.Append(HORIZONTAL_RULE);
            Log.Append(NEW_LINE);
            Log.AppendFormat(SYNC_STARTED, start);
            Log.Append(NEW_LINE);
            Log.AppendFormat("Local Directory: {0}", TechnullogyConfiguration.LocalDirectory);
            Log.Append(NEW_LINE);
            Log.AppendFormat("Remote Directory: {0}", TechnullogyConfiguration.RemoteDirectory);
        }

        public static void LogDirectoryDeleteStarted(DateTime start)
        {
            Console.WriteLine(String.Format(SYNC_STARTED, start));

            Log.Append(NEW_LINE);
            Log.Append(HORIZONTAL_RULE);
            Log.Append(NEW_LINE);
            Log.AppendFormat(SYNC_STARTED, start);
            Log.Append(NEW_LINE);
            Log.AppendFormat("Local Directory: {0}", TechnullogyConfiguration.LocalDirectory);
            Log.Append(NEW_LINE);
            Log.AppendFormat("Remote Directory: {0}", TechnullogyConfiguration.RemoteDirectory);
        }

        public static void LogLoadDirectories(String directoryPath)
        {
            Console.WriteLine(String.Format(LOADING_DIR, directoryPath));

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(LOADING_DIR, directoryPath);
        }

        public static void LogSyncStart(String source, String destination)
        {
            Console.WriteLine(String.Format(COPYING_FILE, source, destination));

            Log.Append(NEW_LINE);
            Log.Append(NEW_LINE);
            Log.AppendFormat(COPYING_FILE, source, destination);
        }

        public static void LogDirectoryCreation(String directory)
        {
            Console.WriteLine(String.Format(CREATING_DIR, directory));

            IncrementDirectoryCreateCount();

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(CREATING_DIR, directory);
        }

        public static void LogDirectoryDelete(String directory)
        {
            Console.WriteLine(String.Format(DIR_DELETED, directory));

            IncrementDirectoryDeleteCount();

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(DIR_DELETED, directory);
        }

        public static void LogDirectoryExists(String directory)
        {
            Console.WriteLine(String.Format(DIR_EXISTS, directory));

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(DIR_EXISTS, directory);
        }

        public static void LogFileCopy(String source, String destination)
        {
            Console.WriteLine(String.Format(COPYING_FILE, source, destination));

            IncrementFileCopyCount();
            
            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(COPYING_FILE, source, destination);
        }

        public static void LogFileExists(String file)
        {
            Console.WriteLine(String.Format(FILE_EXISTS, file));

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(FILE_EXISTS, file);
        }

        public static void LogFileSkipped(String file)
        {
            Console.WriteLine(String.Format(FILE_SKIPPED, file));

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(FILE_SKIPPED, file);
        }

        public static void LogFileDeleted(String file)
        {
            Console.WriteLine(String.Format(FILE_DELETED, file));

            IncrementFileDeleteCount();

            if (!TechnullogyConfiguration.EnableVerboseLogging)
                return;

            Log.Append(NEW_LINE);
            Log.AppendFormat(FILE_DELETED, file);
        }

        public static void LogDirectorySyncFinished(DateTime start, DateTime finish)
        {
            TimeSpan duration = finish - start;

            Log.Append(NEW_LINE);
            Log.Append(NEW_LINE);
            Log.AppendFormat(SYNC_FINISHED, finish);
            Log.Append(NEW_LINE);
            Log.AppendFormat(SYNC_DURATION, duration);
            Log.Append(NEW_LINE);
            Log.Append(HORIZONTAL_RULE);
            Log.AppendFormat("{0}{0}{0}", NEW_LINE);

            Console.WriteLine("Writing Log file");

            WriteLogFile(TechnullogyConfiguration.SyncLogFileLocation);

            Console.WriteLine(SYNC_FINISHED, finish);
            Console.WriteLine(SYNC_DURATION, duration);
            Console.WriteLine("Press the 'Enter' key to exit");
            Console.ReadLine();
        }

        public static void LogDirectoryDeleteFinished(DateTime start, DateTime finish)
        {
            TimeSpan duration = finish - start;

            Log.Append(NEW_LINE);
            Log.Append(NEW_LINE);
            Log.AppendFormat(DELETE_FINISHED, finish);
            Log.Append(NEW_LINE);
            Log.AppendFormat(DELETE_DURATION, duration);
            Log.Append(NEW_LINE);
            Log.Append(HORIZONTAL_RULE);
            Log.AppendFormat("{0}{0}{0}", NEW_LINE);

            Console.WriteLine("Writing Log file");

            WriteLogFile(TechnullogyConfiguration.EmptyDirectoryLogFileLocation);

            Console.WriteLine(DELETE_FINISHED, finish);
            Console.WriteLine(DELETE_DURATION, duration);
            Console.WriteLine("Press the 'Enter' key to exit");
            Console.ReadLine();
        }

        public static void LogCopyStats()
        {
            if (IsLocalToRemote)
            {
                Console.WriteLine(DIRS_CREATED, LocalToRemoteDirectoryCount);
                Console.WriteLine(FILES_CREATED, LocalToRemoteFileCount);

                Log.Append(NEW_LINE);
                Log.AppendFormat(DIRS_CREATED, LocalToRemoteDirectoryCount);
                Log.Append(NEW_LINE);
                Log.AppendFormat(FILES_CREATED, LocalToRemoteFileCount);
            }
            else
            {
                Console.WriteLine(DIRS_CREATED, RemoteToLocalDirectoryCount);
                Console.WriteLine(FILES_CREATED, RemoteToLocalFileCount);

                Log.Append(NEW_LINE);
                Log.AppendFormat(DIRS_CREATED, RemoteToLocalDirectoryCount);
                Log.Append(NEW_LINE);
                Log.AppendFormat(FILES_CREATED, RemoteToLocalFileCount);
            }
        }

        public static void LogDeleteStats()
        {
            if (IsLocalToRemote)
            {
                Console.WriteLine(DIRS_DELETED, LocalDirectoriesDeleteCount);
                Console.WriteLine(FILES_DELETED, LocalFilesDeleteCount);

                Log.Append(NEW_LINE);
                Log.AppendFormat(DIRS_DELETED, LocalDirectoriesDeleteCount);
                Log.Append(NEW_LINE);
                Log.AppendFormat(FILES_DELETED, LocalFilesDeleteCount);
            }
            else
            {
                Console.WriteLine(DIRS_DELETED, RemoteDirectoriesDeleteCount);
                Console.WriteLine(FILES_DELETED, RemoteFilesDeleteCount);

                Log.Append(NEW_LINE);
                Log.AppendFormat(DIRS_DELETED, RemoteDirectoriesDeleteCount);
                Log.Append(NEW_LINE);
                Log.AppendFormat(FILES_DELETED, RemoteFilesDeleteCount);
            }
        }

        public static void LogOverwritingFile(String source, String destination, long sourceSize, long destinationSize)
        {
            Console.WriteLine(String.Format(OVERWRITING_FILE, destination, destinationSize, source, sourceSize));

            if (TechnullogyConfiguration.EnableVerboseLogging)
            {
                Log.Append(NEW_LINE);
                Log.AppendFormat(OVERWRITING_FILE, destination, destinationSize, source, sourceSize);
            }

        }

        public static void LogException(Exception ex)
        {
            Console.WriteLine(ex.Message);

            Log.AppendFormat("Technullogy Directory Sync ERROR: {0}{1}SOURCE:{2}{1}{1}", ex.Message, NEW_LINE, ex.Source);
        }

        private static void WriteLogFile(String logFileLocation)
        {
            if (TechnullogyConfiguration.AppendLogFile)
                File.AppendAllText(logFileLocation, Log.ToString());
            else
            {
                File.Open(logFileLocation, FileMode.Truncate).Close();
                File.AppendAllText(logFileLocation, Log.ToString());
            }
        }

        private static void IncrementFileCopyCount()
        {
            if (IsLocalToRemote)
                LocalToRemoteFileCount += 1;
            else
                RemoteToLocalFileCount += 1;
        }

        private static void IncrementFileDeleteCount()
        {
            if (IsLocalToRemote)
                LocalFilesDeleteCount += 1;
            else
                RemoteFilesDeleteCount += 1;
        }

        private static void IncrementDirectoryCreateCount()
        {
            if (IsLocalToRemote)
                LocalToRemoteDirectoryCount += 1;
            else
                RemoteToLocalDirectoryCount += 1;
        }

        private static void IncrementDirectoryDeleteCount()
        {
            if (IsLocalToRemote)
                LocalDirectoriesDeleteCount += 1;
            else
                RemoteDirectoriesDeleteCount += 1;
        }

        #endregion
    }
}